package cn.firecode.data_collect.service.impl;

import cn.firecode.data_collect.domain.entity.*;
import cn.firecode.data_collect.exception.DcsException;
import cn.firecode.data_collect.mapper.CollectDataTMapper;
import cn.firecode.data_collect.service.CollectDataTService;
import cn.firecode.data_collect.service.CollectEnvironmentTService;
import cn.firecode.data_collect.service.CollectObjectTService;
import cn.firecode.data_collect.utils.*;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.omg.CORBA.TRANSACTION_UNAVAILABLE;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author yangfan
 * @since 2019-12-11
 */
@Service
@Slf4j
public class CollectDataTServiceImpl extends ServiceImpl<CollectDataTMapper, CollectDataT> implements CollectDataTService {

    @Autowired
    private CollectEnvironmentTService environmentTService;

    @Autowired
    private CollectObjectTService objectTService;

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private FastDFSClientUtil fastDFSClientUtil;

    @Autowired
    private FreeChartUtil freeChartUtil;

    @Autowired
    private CollectDataTMapper dataTMapper;

    @Value("${spring.redis.host}")
    private String redisHost;

    @Value("${spring.redis.port}")
    private String redisPort;

    @Value("${spring.redis.database}")
    private String redisDB;

    @Value("${collect.fileLoclCache}")
    private String fileLocalFolder;

    @Value("${collect.redisCachePrefix}" )
    private String redisCachePrefix;

    @Value("${fdfs.reqHost}" )
    private String fdfsHost;

    @Value("${fdfs.reqPort}" )
    private String fdfsPort;


    @Override
    public boolean updateParToRedis(Integer currentUserId, CollectDataT dataT) throws DcsException {
        CollectDataT orginData = getDataFromRedis(currentUserId);
        if(orginData==null){
            log.error("current cache data not exits");
            throw new DcsException("不存在原始记录，无法更新");
        }
        orginData.setText(dataT.getText());
        orginData.setBeforeNdi(dataT.getBeforeNdi());
        orginData.setAfterNdi(dataT.getAfterNdi());
        orginData.setFeedSpeed(dataT.getFeedSpeed());
        orginData.setRobotJoint(dataT.getRobotJoint());
        orginData.setMotorSpeed(dataT.getMotorSpeed());
        orginData.setHeightOffset(dataT.getHeightOffset());
        orginData.setDrillPunchCount(dataT.getDrillPunchCount());
        redisUtil.set(redisCachePrefix + currentUserId,orginData);
        return true;
    }

    @Override
    public boolean createDataToRedis(Integer currentUserId, CollectDataT dataT) throws DcsException {
        CollectDataT dataTemp = getDataFromRedis(currentUserId);
        if(dataTemp!=null){
            log.error("current user has unfinished collection records: {}",currentUserId);
            throw  new DcsException("当前用户存在未完成的临时记录");
        }
        //Check the required parameters
        Integer environmentId = dataT.getEnvironmentId();
        Integer objectId = dataT.getObjectId();
        if(environmentId==null||objectId==null){
            log.error("environmentId or objectId is empty");
            throw  new DcsException("采集环境和采集对象参数不能为空");
        }
        CollectObjectT objectT = objectTService.getById(objectId);
        CollectEnvironmentT environmentT = environmentTService.getById(environmentId);
        if(environmentT==null||objectT==null||environmentT.getStatus()==1||objectT.getIsCollect()!=0){
            log.error("environmentId or objectId is error");
            throw  new DcsException("采集编号或对象编号错误,无法找到对应记录或对应记录不能操作");
        }
        CollectDataT data_temp = new CollectDataT();
        Integer tempDataId = RandomUtil.randomInt(100,20000);
        data_temp.setEnvironmentId(environmentId);
        data_temp.setObjectId(objectId);
        data_temp.setDataId(tempDataId);
        data_temp.setStatus(0);
        data_temp.setForceFile("");
        data_temp.setCreateTime(LocalDate.now());
        data_temp.setDrillPunchCount(0);
        data_temp.setHeightOffset(0.0);
        data_temp.setMotorSpeed(0.0);
        data_temp.setRobotJoint("");
        data_temp.setFeedSpeed(0.0);
        data_temp.setText("");
        data_temp.setBeforePunchImg("");
        data_temp.setAfterPunchImg("");
        data_temp.setBeforeNdi("");
        data_temp.setAfterNdi("");
        data_temp.setForceThumbnail("");
        redisUtil.set(redisCachePrefix + currentUserId,data_temp);

        CollectDataT checkIsStore = getDataFromRedis(currentUserId);
        if(checkIsStore==null){
            log.error("store to redis error can not store or stored a error data");
            throw  new DcsException("临时数据对象缓存失败，无法缓存到redis或缓存数据不一致");
        }
        return true;
    }

    @Override
    public CollectDataT getDataFromRedis(Integer customerId) {
        log.info("get data form redis :"+customerId);
        return (CollectDataT) redisUtil.get(redisCachePrefix + customerId);
    }

    @Override
    public boolean deleteDataFormRedis(Integer customerId) throws DcsException{
        CollectDataT dataT = getDataFromRedis(customerId);
        if(dataT==null){
            log.error("current user:{} not hava data",customerId);
            throw  new DcsException("当前用户不存在临时记录");
        }
        redisUtil.del(redisCachePrefix + customerId);
        CollectDataT temp = getDataFromRedis(customerId);
        if(temp!=null){
            log.error("delete data from redis error");
            throw  new DcsException("数据缓存记录失败，没有成功删除");
        }
        Integer count = (Integer) redisUtil.get("Collect_Count");
        for(int i = 1;i<=count;i++){
            redisUtil.del(String.valueOf(i));
        }
        redisUtil.set("Collect_Count",0);
        return true;
    }

    @Override
    public boolean storeRemoteFile(InputStream fileInputStream, DcsFileEnum fileType,Integer customerId, String fileExname) throws DcsException{
        String localFileCachePath = fileLocalFolder+ File.separator+"cache_"+customerId+"_"+fileType.getTypeName()+"."+fileExname;
        log.info("local file cache path is {}",localFileCachePath);
        File localFile = FileUtil.writeFromStream(fileInputStream, localFileCachePath);
        if(!localFile.exists()||FileUtil.size(localFile)==0){
            log.error("local file cache:{} store error" , localFileCachePath);
            throw  new DcsException("本地文件缓存失败："+localFileCachePath);
        }
        try {
            String fastDfsPath = fastDFSClientUtil.uploadJsonFile(localFile, fileExname);
            CollectDataT dataT = getDataFromRedis(customerId);
            if(dataT==null){
                log.error("current user not have data cache");
                throw new DcsException("当前用户不存在通道缓存");
            }
            if(fileType==DcsFileEnum.IMG_BEFORE){
                dataT.setBeforePunchImg(fdfsHost+":"+fdfsPort+"/"+fastDfsPath);
            }else if(fileType == DcsFileEnum.IMG_AFTER){
                dataT.setAfterPunchImg(fdfsHost+":"+fdfsPort+"/"+fastDfsPath);
            }else if(fileType == DcsFileEnum.FORCE_FILE){
                dataT.setForceFile(fdfsHost+":"+fdfsPort+"/"+fastDfsPath);
            }
            boolean setResult = redisUtil.set(redisCachePrefix + customerId, dataT);
            if(setResult){
                return true;
            }else {
                return false;
            }
        } catch (IOException e) {
            throw new DcsException("FastDFS 文件上传失败;file:"+localFile+";error:"+e.getMessage());
        }
    }

    @Override
    public boolean deleteLocalCacheFile(Integer customerId) {
        List<File> files = FileUtil.loopFiles(fileLocalFolder);
        for(File file : files){
            String fileName = file.getName();
            log.debug("file list item :{}",fileName);
            if(fileName.startsWith("cache_"+customerId)){
                log.info("file name match:"+fileName);
                boolean del = FileUtil.del(file.getAbsolutePath());
                log.info("file is deleted:"+fileName+":"+del);
            }
        }
        return true;
    }

    @Override
    public boolean chechFileMD5(InputStream fileInputStream, String originalMD5) {
        String localFileMD5 = SecureUtil.md5(fileInputStream).toLowerCase();
        originalMD5 = originalMD5.toLowerCase();
        if(originalMD5.equals(localFileMD5)){
            return true;
        }
        log.error("MD5 file check failed");
        return false;
    }

    @Override
    public boolean storeCollectTypeToRedis(Integer currentUserId, Integer collectType) throws DcsException{
        Integer checkHasRecord = getCollectTypeFormRedis(currentUserId);
        if(checkHasRecord!=null){
            log.error("current cuser has unfinished collectType record");
            throw  new DcsException("当前用户存在未完成的记录");
        }
        redisUtil.set("data_collect_type_" + currentUserId,collectType.intValue());
        Integer checkHasStore = getCollectTypeFormRedis(currentUserId);
        if(checkHasStore!=collectType){
            log.error("cache error can not cache or cache collectType data inconsistency");
            throw  new DcsException("无法缓存数据或缓存数据不一致");
        }
        return true;
    }

    @Override
    public Integer getCollectTypeFormRedis(Integer currentUserId) {
        log.info("get collect type form redis");
        return (Integer) redisUtil.get("data_collect_type_" + currentUserId);
    }

    @Override
    public boolean deleteCollectTypeFormRedis(Integer currentUserId) throws DcsException{
        Integer temp = getCollectTypeFormRedis(currentUserId);
        if(temp==null){
            log.error("current user collect Type cache data inexistence");
            throw  new DcsException("当前用户存不在未完成的记录");
        }
        redisUtil.del("data_collect_type_" + currentUserId);
        Integer checkIsDelete = getCollectTypeFormRedis(currentUserId);
        if(checkIsDelete!=null){
            log.error("The data was not deleted successfully");
            throw  new DcsException("数据缓存无法成功删除");
        }
        return true;
    }

    @Override
    public boolean createLineChartForForceZ(Integer currentUserId) throws DcsException{
        Integer collectType = getCollectTypeFormRedis(currentUserId);
        CollectDataT dataT = getDataFromRedis(currentUserId);
        if(dataT==null){
            log.error("current data cache not exists");
            throw  new DcsException("当前用户没有通道缓存记录");
        }
        List<ForceRealtime> forceRealtimes = new ArrayList<>();
        String localForceFilePath = fileLocalFolder+ File.separator+"cache_"+currentUserId+"_"
                +DcsFileEnum.FORCE_FILE.getTypeName()+".json";
        if(collectType==1){
            forceRealtimes = readForceFormRedis();
            //上传文件到fastDFS中
            String jsonString = JSON.toJSONString(forceRealtimes);
            File file = FileUtil.writeString(jsonString, localForceFilePath, "utf-8");
            try {
                String fastDfsFilePath = fastDFSClientUtil.uploadJsonFile(file, "json");
                dataT.setForceFile(fdfsHost+":"+fdfsPort+"/"+fastDfsFilePath);
                redisUtil.set(redisCachePrefix+currentUserId,dataT);
            } catch (IOException e) {
                log.info("json file upload fastDFS error:{}",e.getMessage());
                throw new DcsException("力反馈数据转存到fastDFS失败");
            }
        }else if(collectType==2){
            File localForceFile = new File(localForceFilePath);
            if(!localForceFile.exists()||FileUtil.size(localForceFile)==0){
                log.warn("当前本地力反馈文件缓存不存在!");
                String fastDfsPath = dataT.getForceFile().substring(fdfsHost.length()+fdfsPort.length()+3);
                if(fastDfsPath.isEmpty()){
                    log.error("力反馈文件不存在");
                    throw new DcsException("力反馈文件不存在");
                }
                int index_temp = fastDfsPath.indexOf("/");
                InputStream download = fastDFSClientUtil.download(fastDfsPath.substring(0, index_temp),
                        fastDfsPath.substring(index_temp + 1, fastDfsPath.length()));
                FileUtil.writeFromStream(download,localForceFilePath);
            }

            forceRealtimes = readForceFormLocalFile(localForceFilePath);

        }

        if(forceRealtimes.size()==0){
            log.warn("当前获取到的力反馈数据量为0");
            throw new DcsException("当前获取到的力反馈数据量为0");
        }

        String chartFilePath = freeChartUtil.getChart(forceRealtimes, "cache_"+currentUserId+"_thumZ" , fileLocalFolder);
        File lineChartFile = new File(chartFilePath);
        if(!lineChartFile.exists()||FileUtil.size(lineChartFile)==0){
            log.error("linechart file error not exists or the file size is 0");
            throw new DcsException("自动生成力反馈缩略图出错");
        }
        try {
            String forceThumFilePath = fastDFSClientUtil.uploadJsonFile(lineChartFile, FileUtil.extName(lineChartFile));
            dataT.setForceThumbnail(fdfsHost+":"+fdfsPort+"/"+forceThumFilePath);
            redisUtil.set(redisCachePrefix + currentUserId,dataT);
            log.info("create thum succeed the data is :"+dataT.toString());
            return true;
        } catch (IOException e) {
            log.error("upload force thum file error cant upload to fastDFS");
            throw new DcsException("力反馈缩略图上传失败");
        }
    }

    @Override
    public boolean checkDataIsIntact(Integer currentUserId) throws DcsException {
        CollectDataT dataT = getDataFromRedis(currentUserId);
        if(dataT.getAfterNdi().isEmpty()){
            throw new DcsException("数据不完整:AfterNdi");
        }
        if(dataT.getAfterPunchImg().isEmpty()){
            throw new DcsException("数据不完整:afterPunchImg");
        }
        if(dataT.getBeforeNdi().isEmpty()){
            throw new DcsException("数据不完整:BeforeNdi");
        }
        if(dataT.getBeforePunchImg().isEmpty()){
            throw new DcsException("数据不完整:BeforePunchImg");
        }
        if(dataT.getText().isEmpty()){
            throw new DcsException("数据不完整:Text");
        }
        return true;
    }

    @Override
    public boolean destroyCacheFileFastDfs(Integer currentUserId) throws DcsException {
        CollectDataT dataT = getDataFromRedis(currentUserId);
        if(dataT==null){
            log.error("current usr not have chche data in redis");
            throw  new DcsException("当前用户不存在缓存数据");
        }
        if(dataT.getForceFile()!=null){
            fastDFSClientUtil.delFile(dataT.getForceThumbnail().substring(fdfsHost.length()+fdfsPort.length()+3));
        }
        if(dataT.getBeforePunchImg()!=null){
            fastDFSClientUtil.delFile(dataT.getBeforePunchImg().substring(fdfsHost.length()+fdfsPort.length()+3));
        }
        if(dataT.getAfterPunchImg()!=null){
            fastDFSClientUtil.delFile(dataT.getAfterPunchImg().substring(fdfsHost.length()+fdfsPort.length()+3));
        }

        return true;
    }

    @Override
    public void createDataToRedis(int count) {
        for (int i=0;i<count;i++ ){
            ForceRealtime forceRealtime = new ForceRealtime();
            forceRealtime.setId(i+1);
            forceRealtime.setDepth(i*0.01);
            forceRealtime.setSpeed(3+ RandomUtil.randomDouble(0.1,1));
            Force force = new Force();
            force.setX(RandomUtil.randomDouble());
            force.setY(RandomUtil.randomDouble());
            force.setZ(RandomUtil.randomDouble());
            force.setMx(RandomUtil.randomDouble());
            force.setMy(RandomUtil.randomDouble());
            force.setMz(RandomUtil.randomDouble());
            forceRealtime.setForce(force);
            redisUtil.set(String.valueOf(i+1),JSON.toJSONString(forceRealtime));
            redisUtil.set("Collect_Count",count);
        }
    }

    @Override
    public int insertAndGetId(CollectDataT dataT) {
        return dataTMapper.insertAndGetId(dataT);
    }


    private  List<ForceRealtime> readForceFormRedis() throws DcsException{
        Integer collect_count = (Integer) redisUtil.get("Collect_Count");
        List<ForceRealtime> forceRealtimes = new ArrayList<>();
        log.info("current redis has force data item count:{}",collect_count);
        for(int i=1;i<=collect_count;i++){
            try {
                JSONObject forceData = JSON.parseObject((String) redisUtil.get(String.valueOf(i)));
                ForceRealtime forceRealtime = forceData.toJavaObject(ForceRealtime.class);
                forceRealtimes.add(forceRealtime);
            }catch (Exception e){
                log.error("json string parse to force object error:{},the keu is:{},value is:{}",
                        e.getMessage(),i,(String) redisUtil.get(String.valueOf(i)));
                throw new DcsException("redis中数据:"+i+"存储的对象非力反馈数据");
            }
        }
        log.info("the force list size is :{}",forceRealtimes.size());
        return forceRealtimes;
    }

    private List<ForceRealtime> readForceFormLocalFile(String filePath) throws  DcsException{
        File forceFile = new File(filePath);
        if(!forceFile.exists()||FileUtil.size(forceFile)==0){
            log.error("the file path:{} is not exit",filePath);
            throw new DcsException("文件不存在");
        }
        String jsonString = FileUtil.readString(filePath, "utf-8");
        List<ForceRealtime> forceRealtimes = JSON.parseArray(jsonString, ForceRealtime.class);
        return forceRealtimes;
    }

}
